package cn.walls1717.juc.future;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

/**
 * 体验FutureTask异步编排
 *
 * @author walls1717
 * @create 2022/12/08 20:38
 **/
@Slf4j
public class FutureThreadPoolDemo {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        m1();
        System.out.println("--------------");
        m2();
    }

    /**
     * 方法串行执行，耗时为所有业务的总耗时。大约耗时490ms
     *
     * @throws InterruptedException .
     */
    private static void m1() throws InterruptedException {
        long start = System.currentTimeMillis();
        TimeUnit.MILLISECONDS.sleep(300);
        TimeUnit.MILLISECONDS.sleep(100);
        TimeUnit.MILLISECONDS.sleep(90);
        long end = System.currentTimeMillis();
        log.info("耗时 -> {}", end - start);
    }

    /**
     * 开启多个线程异步执行，性能会稍微好点，大约耗时340-440ms
     *
     * @throws InterruptedException 。
     * @throws ExecutionException 。
     */
    private static void m2() throws InterruptedException, ExecutionException {
        // 开启线程池，指定线程数为3个。
        ExecutorService executor = Executors.newFixedThreadPool(3);

        long start = System.currentTimeMillis();
        // 开启线程1
        FutureTask<String> futureTask1 = new FutureTask<>(() -> {
            TimeUnit.MILLISECONDS.sleep(300);
            return "futureTask1";
        });
        executor.submit(futureTask1);
        // 开启线程2
        FutureTask<String> futureTask2 = new FutureTask<>(() -> {
            TimeUnit.MILLISECONDS.sleep(100);
            return "futureTask2";
        });
        executor.submit(futureTask2);

        /*
         * 主线程任务执行任务，主线程任务的执行顺序会极大程度的影响性能。
         * 将主线成的任务放在等待两个异步线程之后，性能就会比将其放在之前差很多。
         * 因为get方法会造成阻塞，必须等待futureTask执行完成返回结果后才会执行下面的代码。
         */
        TimeUnit.MILLISECONDS.sleep(90);

        // 等待两个线程的执行结果
        log.info("futureTask1 result is {}", futureTask1.get());
        log.info("futureTask2 result is {}", futureTask2.get());

        long end = System.currentTimeMillis();
        // 关闭线程池
        executor.shutdown();
        log.info("耗时 -> {}", end - start);
    }
}
